﻿using Exiled.API.Features;
using Newtonsoft.Json;
using RemoteAdmin;
using RgCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using JsonMessage;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using PlayerRoles;
using UnityEngine;

namespace ServerQuery
{
    public class ServerQueryPlugin : RgPlugin
    {
        public override string Name => "服务器远程查询";

        public override string Id => "server_query";
        public override void OnEnabled()
        {
            SocketData.SetEnabled(true);
        }
        public override void OnDisabled()
        {
            SocketData.SetEnabled(false);
        }
    }
    public class BotCommandSender : CommandSender
    {
        public static BotCommandSender Instance = new BotCommandSender();
        public override bool FullPermissions => true;

        public override byte KickPower => byte.MaxValue;

        public override string Nickname => "QQ机器人";

        public override ulong Permissions => ServerStatic.PermissionsHandler.FullPerm;

        public override string SenderId => "QQ BOT";

        public override void Print(string text)
        {
            Log.Info("[QQBot Print] " + text);
        }

        public override void RaReply(string text, bool success, bool logToConsole, string overrideDisplay)
        {
            SocketData.Response = text;
            SocketData.Success = success;
        }
    }
    public static class SocketData
    {
        public static bool Success;
        public static string Response;
        public static Socket ServerSocket;
        public static Socket Socket;
        public static Thread ListenThread;

        public static QueryConfig Config => RgCore.RgCore.instance.Config.ServerQuery;

        public static void SetEnabled(bool enable)
        {
            if (enable)
            {
                    Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    Socket.Bind(new IPEndPoint(IPAddress.Parse(Config.IpAddress), (int)Config.Port));
                    Socket.Listen(5);
                    Log.Info("服务器Socket查询系统已启动 服务器名:" + Config.ServerName);
                    ListenThread = new Thread(Listen);
                    ListenThread.Start();
            }
            else
            {
                Socket.Close();
                ListenThread.Abort();
            }
        }

        public static void ExecuteCommand(string cmd, out bool success, out string response)
        {
            CommandProcessor.ProcessQuery(cmd, BotCommandSender.Instance);
            success = SocketData.Success;
            response = SocketData.Response;
        }
        public static PlayerData GetPlayerData(Player player)
        {
            Color32 c = player.Role.Base.RoleColor;
            JsonMessage.Color color = new JsonMessage.Color()
            {
                Red = c.r,
                Blue = c.g,
                Green = c.b
            };
            return new PlayerData()
            {
                Id = player.Id,
                UserId = player.UserId,
                RoleColor = color,
                RoleName = player.Role.Base.RoleName
            };
        }
        public static void Listen()
        {
            while (true)
            {
                try
                {
                    ServerSocket = Socket.Accept();
                    byte[] buffer = new byte[1024];
                    int count = ServerSocket.Receive(buffer);
                    string str = Encoding.UTF8.GetString(buffer, 0, count);
                    var query = JsonConvert.DeserializeObject<Query>(str);
                    string output = "unknown";
                    if (query != null)
                    {
                        switch ((QueryType)query.Operation)
                        {
                            case QueryType.ServerData:
                                {
                                    List<PlayerData> list = new List<PlayerData>();
                                    foreach (Player player in Player.List)
                                    {
                                        list.Add(GetPlayerData(player));
                                    }
                                    ServerData sd = new ServerData()
                                    {
                                        ServerName = Config.ServerName,
                                        StartTime = Round.InProgress ? Round.StartedTime : DateTime.MinValue,
                                        Admins = Player.List.Count(x => x.RemoteAdminAccess),
                                        MaxPlayers = CustomNetworkManager.slots,
                                        Players = Server.PlayerCount,
                                        ReservationSlotRemains = -1,
                                        PlayerList = list
                                    };
                                    output = JsonConvert.SerializeObject(sd);
                                    break;
                                }
                            case QueryType.PlayerQuery:
                                {
                                    if (query.Parameters.Length == 0)
                                    {
                                        output = "parameter_error";
                                        break;
                                    }
                                    Player player = int.TryParse(query.Parameters[0], out int id) ? Player.Get(id) : Player.Get(query.Parameters[0]);
                                    if (player == null)
                                    {
                                        output = "invaild_identity";
                                        break;
                                    }
                                    output = JsonConvert.SerializeObject(GetPlayerData(player));
                                    break;
                                }
                            case QueryType.BanPlayer:
                                {
                                    if (query.Parameters.Length < 4)
                                    {
                                        output = "parameter_error";
                                        break;
                                    }
                                    bool id_query = int.TryParse(query.Parameters[0], out int id);
                                    Player player = id_query ? Player.Get(id) : Player.Get(query.Parameters[0]);
                                    if (player != null)
                                    {
                                        string cmd = $"ban {player.Id} {int.Parse(query.Parameters[2])} {query.Parameters[3]}";
                                        CommandProcessor.ProcessQuery(cmd, BotCommandSender.Instance);
                                        output = "success";
                                    }
                                    else if (id_query)
                                    {
                                        output = "not_exist";
                                    }
                                    else
                                    {
                                        string cmd = $"oban {query.Parameters[1]} {int.Parse(query.Parameters[2])} {query.Parameters[3]}";
                                        CommandProcessor.ProcessQuery(cmd, BotCommandSender.Instance);
                                        output = "success";
                                    }
                                    break;
                                }
                            case QueryType.UpdateReservation:
                                {
                                    break;
                                }
                        }
                    }
                }
                catch(Exception e)
                {
                    Log.Error("ServerQuery异常：" + e);
                }
                ServerSocket.Close();
            }
        }
    }
}
